<template>
  <div>
    <!--  默认type为submit，当为submit时点击按钮后会将模态框关闭  -->
    <button type="button" class="btn btn-white btn-default btn-round" @click="selectFile()">
      <i class="ace-icon fa fa-cloud-upload"></i>
      {{ text }}
    </button>
    <input class="hidden" ref="file" type="file" v-on:change="uploadFile()" v-bind:id="inputId + '-input'"/>
  </div>
</template>

<script>
export default {
  name: "big-file",
  // 组件对外暴露可配置的属性
  props: {
    // 父组件中的回调文本和方法
    text: {
      default: "上传大文件"
    },
    inputId: {
      default: "file-upload"
    },
    suffixs: {
      default: []
    },
    use: {
      default: ""
    },
    afterUpload: {
      type: Function,
      default: null
    }
  },
  data: function () {
    return {
    }
  },
  methods: {
    // 上传文件的方法
    uploadFile() {
      let _this = this;
      let file = _this.$refs.file.files[0];

      // 判断文件格式
      let suffixs = _this.suffixs;
      // 得到文件的名称
      let fileName = file.name;
      // 通过文件名称获取到文件的类型
      let suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
      // 定义初始的后缀校验变量，初始值为不能通过
      let validateSuffix = false;
      for (let i = 0; i < suffixs.length; i++) {
        // 因为文件格式后缀有大小写的区别，因此统一转为小写格式来进行判断
        if (suffixs[i].toLowerCase() === suffix) {
          // 如果校验通过则说明上传的文件为合法文件
          validateSuffix = true;
          break;
        }
      }

      if (!validateSuffix) {
        Toast.warning("文件格式不正确！支持上传的格式为：" + suffixs.join("，"));
        // 清空拦截到的文件对象
        $("#" + _this.inputId + "-input").val("");
        return;
      }

      // 文件分片
      let shardSize = 10 * 1024 * 1024;  // 以10MB为一个分片
      let shardIndex = 1;  // 分片索引，1表示第一个分片

      let size = file.size; // 获取文件的大小
      let shardTotal = Math.ceil(size / shardSize);  // 文件大小与分片大小的比值为分片总数

      // 定义文件的标识，标识多次上传的不是同一个文件
      let key = hex_md5(file.name + file.size + file.type);
      // 将生成的十六进制数据转换为十进制
      let key10 = parseInt(key, 16);
      // 再将得到的十进制数据转换为六十二进制的数据 => 26个大写字母 + 26个小写字母 + 10个阿拉伯数字总共62个字符
      let key62 = Tool._10to62(key10)

      let param = {
        'shardIndex': shardIndex,
        'shardSize': shardSize,
        'shardTotal': shardTotal,
        'use': _this.use,
        'name': file.name,
        'suffix': suffix,
        'size': file.size,
        'key': key62
      };

      _this.check(param);
    },

    /**
     * 检查文件的上传状态，是否已经上传过？上传到了第几个分片？
     *
     * @param param
     */
    check(param) {
      let _this = this;
      _this.$ajax.get(process.env.VUE_APP_SERVER + '/file/admin/check/' + param.key).then((response) => {
        let result = response.data;
        if (result.success) {
          let obj = result.content;
          // 如果上传的文件为空
          if (!obj) {
            param.shardIndex = 1;
            console.log("没有找到对应的文件记录，开始从第一个分片上传");
            // 开始上传文件
            _this.upload(param);
          } else if (obj.shardIndex === obj.shardTotal) {
            // 已上传分片 = 分片总数 此时说明已经上传完成，不需要再进行上传
            Toast.success("文件极速秒传成功");
            _this.afterUpload(result);
            // 在文件上传完成之后将控件中的值进行清空
            $("#" + _this.inputId + "-input").val("");
          } else {
            // 从下一个分片开始上传
            param.shardIndex = obj.shardIndex + 1;
            console.log("找到了对应的分片记录，从分片" + param.shardIndex + "开始上传");
            // 开始上传文件
            _this.upload(param);
          }
        } else {
          Toast.warning("文件上传失败");
          // 在文件上传完成之后将控件中的值进行清空
          $("#" + _this.inputId + "-input").val("");
        }
      });
    },

    getFileShard: function (shardIndex, shardSize) {
      let _this = this;
      let file = _this.$refs.file.files[0];
      let start = (shardIndex - 1) * shardSize;   // 当前分片的起始位置
      // 如果计算出的分片大小比文件本身大小还要大的话，此时的分片大小取文件的大小
      let end = Math.min(file.size, start + shardSize);     // 当前分片的结束位置
      // 从文件中截取分片数据
      let fileShard = file.slice(start, end);
      return fileShard;
    },

    upload: function (param) {
      let _this = this;
      let shardIndex = param.shardIndex;
      let shardTotal = param.shardTotal;
      let shardSize = param.shardSize;
      let fileShard = _this.getFileShard(shardIndex, shardSize);
      // 将图片转为Base64进行传输
      let fileReader = new FileReader();

      // 显示上传进度条
      Progress.show(parseInt((shardIndex - 1) * 100 / shardTotal));

      // 增加数据读取事件监听
      fileReader.onload = function (e) {
        let base64 = e.target.result;

        param.shard = base64;
        // 打印上传的文件进行解码后的字符串信息
        // console.log("base64", base64);

        _this.$ajax.post(process.env.VUE_APP_SERVER + '/file/admin/upload', param).then((result) => {
          let response = result.data;
          console.log("文件上传成功：", response);

          // 文件上传成功后再次显示上传进度条
          Progress.show(parseInt(shardIndex * 100 / shardTotal));
          // 判断所有分片是否上传完成
          if (shardIndex < shardTotal) {
            // 上传下一个分片
            param.shardIndex = param.shardIndex + 1;
            _this.upload(param);
          } else {
            // 关闭上传进度条的显示框
            Progress.hide();

            _this.afterUpload(response);
            // 在文件上传完成之后将控件中的值进行清空
            // 如果不进行清空值的话，将同一文件反复上传时不会触发change事件
            $("#" + _this.inputId + "-input").val("");
          }

        });
      }
      // 读取到分片数据，当读取到数据时就会触发监听的事件
      fileReader.readAsDataURL(fileShard);
      return shardIndex;
    },

    selectFile() {
      let _this = this;
      // 触发一次点击事件
      $("#" + _this.inputId + "-input").trigger("click");
    },

  }
}
</script>
